package lol.clann.bukkit.pluginboot.util;

import lol.clann.bukkit.pluginboot.PluginBoot;
import lol.clann.bukkit.pluginboot.command.CommandAnnotation;
import lol.clann.bukkit.pluginboot.command.ICommand;
import lol.clann.bukkit.pluginboot.command.Sender;
import lol.clann.bukkit.pluginboot.model.rawmessage.RawMessage;
import lol.clann.bukkit.pluginboot.task.Timer;
import lol.clann.clannboot.annotation.inject.Inject;
import lol.clann.clannboot.annotation.svc.Service;
import lol.clann.clannboot.context.BeanContext;
import lol.clann.clannboot.util.collection.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;

import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.function.Consumer;

/**
 * @author pyz
 * @date 2018/8/15 上午7:56
 */
@Service(priority = Integer.MAX_VALUE)
public class PageUtils extends ICommand implements Listener {

    /**
     * 分页过期时间
     */
    private static final long expireTime = 600 * 1000L;
    private static final int defaultPageSize = 10;
    @Inject
    private Validator validator;
    @Inject
    private PluginBoot pluginLoader;
    private Map<CommandSender, PageMessage> messages = new WeakHashMap<>();

    public PageUtils() {
        super("pageUtils");
    }

    /**
     * 清理过期分页
     */
    @Timer(name = "清理过期分页", async = true, dely = "600000", interval = "600000")
    private void task() {
        long now = System.currentTimeMillis();
        synchronized (messages) {
            MapUtils.removeIf(messages, (k, v) -> now < v.getExpireTime());
        }
    }

    @CommandAnnotation(needOp = false, mustPlayer = true, des = "上一页")
    private void prePage(@Sender CommandSender sender) {
        PageMessage page = messages.get(sender);
        if (page == null) {
            return;
        }
        page.prePage();
        page.sendMessage();
    }

    @CommandAnnotation(needOp = false, mustPlayer = true, des = "下一页")
    private void nextPage(@Sender CommandSender sender) {
        PageMessage page = messages.get(sender);
        if (page == null) {
            return;
        }
        page.nextPage();
        page.sendMessage();
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    private void quit(PlayerQuitEvent event) {
        messages.remove(event.getPlayer());
    }

    private <T> Consumer<T> parseSenderFn(CommandSender sender, List<T> messages) {
        Consumer<T> sendFn = null;
        if (!messages.isEmpty()) {
            T element = messages.get(0);
            if (element instanceof String) {
                sendFn = message -> sender.sendMessage((String) message);
            } else if (element instanceof RawMessage) {
                sendFn = message -> ((RawMessage) message).send(sender);
            }
        }
        return sendFn;
    }

    public <T> void sendPage(CommandSender sender, List<T> messages, int pageSize) {
        sendPage(sender, messages, parseSenderFn(sender, messages), pageSize, null);
    }

    public <T> void sendPage(CommandSender sender, List<T> messages, String header) {
        sendPage(sender, messages, parseSenderFn(sender, messages), defaultPageSize, header);
    }

    public <T> void sendPage(CommandSender sender, List<T> messages) {
        sendPage(sender, messages, parseSenderFn(sender, messages), defaultPageSize, null);
    }

    public <T> void sendPage(CommandSender sender, List<T> messages, Consumer<T> sendFn) {
        sendPage(sender, messages, sendFn, defaultPageSize, null);
    }

    public <T> void sendPage(CommandSender sender, List<T> messages, Consumer<T> sendFn, int pageSize) {
        sendPage(sender, messages, sendFn, pageSize, null);
    }

    public <T> void sendPage(CommandSender sender, List<T> messages, Consumer<T> sendFn, int pageSize, @Nullable String header) {
        PageMessage page = new PageMessage(sender, header, messages, sendFn, pageSize, 0);
        this.messages.put(sender, page);
        page.sendMessage();
    }

    public static class PageMessage<T> {

        /**
         * 分页头
         * <page>会替换为当前页码
         */
        private final String head;
        private final CommandSender sender;
        private final List<T> messages;
        private final Consumer<T> sendFn;
        private final int pageSize;
        @Inject
        private Validator validator;
        @Inject
        private TextUtils textUtils;
        private int page;
        private int totalPage;
        private long expireTime;

        public PageMessage(CommandSender sender, String head, List<T> messages, Consumer<T> sendFn, int pageSize, int page) {
            BeanContext.inject(this);
            this.head = head;
            this.sender = sender;
            this.sendFn = sendFn;
            this.messages = messages;
            this.pageSize = pageSize;
            this.page = page;
            totalPage = messages.size() / pageSize + 1;
            validator.isTrue(page < totalPage, "页码越界");
        }

        public CommandSender getCommandSender() {
            return sender;
        }

        public int getPageSize() {
            return pageSize;
        }

        public int getPage() {
            return page;
        }

        public boolean hasNext() {
            return page < totalPage - 1;
        }

        public boolean hasPre() {
            return page > 0;
        }

        public void nextPage() {
            validator.isTrue(page + 1 < totalPage, "页码越界");
            page++;
        }

        public void prePage() {
            validator.isTrue(page > 0 && page - 1 < totalPage, "页码越界");
            page--;
        }

        public long getExpireTime() {
            return expireTime;
        }

        public void sendMessage() {
            expireTime = System.currentTimeMillis() + expireTime;
            if (!StringUtils.isEmpty(head)) {
                sender.sendMessage(head.replace("<page>", "" + (page + 1)));
            }
            int start = page * pageSize;
            int end = Math.min(start + pageSize, messages.size());
            if (!(sender instanceof Player)) {
                // 非玩家不能点击,需要全部发送
                start = 0;
                end = messages.size();
            }
            for (int i = start; i < end; i++) {
                sendFn.accept(messages.get(i));
            }
            if (sender instanceof Player) {
                RawMessage footer = RawMessage.createRawMessage()
                        .then("上一页");
                if (hasPre()) {
                    footer.color(ChatColor.RED)
                            .runCommand("/pageUtils prePage");
                } else {
                    footer.color(ChatColor.GRAY);
                }
                footer.then("§a==========================");
                footer.then("下一页");
                if (hasNext()) {
                    footer.color(ChatColor.RED)
                            .runCommand("/pageUtils nextPage");
                } else {
                    footer.color(ChatColor.GRAY);
                }
                footer.send(sender);
            }
        }

    }
}
